﻿// -----------------------------------------------------------------------
// <copyright file="PapRequestMessage.cs" company="Zen Design Corp">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Zen.BlackBerry.Pap.Control
{
	using System.IO;
	using System.Xml;
	using System.Xml.Serialization;
	using Microsoft.Practices.ServiceLocation;
	using Zen.BlackBerry.Common;

	/// <summary>
	/// Represents a PAP request message.
	/// </summary>
	/// <remarks>
	/// A PAP request message contains a control part (XML) and an optional
	/// content part.
	/// </remarks>
	public class PapRequestMessage
	{
		private PapControl _control;
		private Content _content;

		/// <summary>
		/// Initializes a new instance of the <see cref="PapRequestMessage"/>
		/// class with only a control part.
		/// </summary>
		/// <param name="control">The control.</param>
		public PapRequestMessage(PapControl control)
		{
			_control = control;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="PapRequestMessage"/>
		/// class with both control and content parts.
		/// </summary>
		/// <param name="control">The control.</param>
		/// <param name="content">The content.</param>
		public PapRequestMessage(PapControl control, Content content)
		{
			_control = control;
			_content = content;

			IBoundaryGenerator bg = ServiceLocator.Current
				.GetInstance<IBoundaryGenerator>();
			Boundary = bg.MakeBoundary();

			if (content != null && control is PushMessageControl)
			{
				string pushIdHeader = content.GetHeader("Push-Message-ID");
				if (string.IsNullOrEmpty(pushIdHeader))
				{
					content.SetHeader(
						"Push-Message-ID",
						((PushMessageControl)control).PushId);
				}
			}
		}

		/// <summary>
		/// Gets or sets a value indicating whether to use a RIM specific
		/// root XML element during serialization.
		/// </summary>
		/// <value>
		/// <c>true</c> if a RIM specific root should be used during 
		/// serialization; otherwise, <c>false</c>.
		/// </value>
		public bool UseRimSpecificRoot
		{
			get;
			set;
		}

		/// <summary>
		/// Gets the boundary identifier when building MIME payload.
		/// </summary>
		/// <value>The boundary.</value>
		/// <remarks>
		/// This will be null for control messages that do not contain any
		/// content part.
		/// </remarks>
		public string Boundary
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets the content type for the HTTP header.
		/// </summary>
		/// <value>The content type for HTTP header.</value>
		/// <remarks>
		/// The content type returned will be &quot;application/xml&quot;
		/// for control messages without content part and 
		/// &quot;multipart/related&quot; for control messages with a content
		/// part.
		/// </remarks>
		public string ContentTypeForHeader
		{
			get
			{
				if (!string.IsNullOrEmpty(Boundary))
				{
					return string.Format(
						"multipart/related; boundary={0}; type=\"application/xml\"",
						Boundary);
				}
				else
				{
					return "application/xml";
				}
			}
		}

		internal PapControl Control
		{
			get
			{
				return _control;
			}
		}

		/// <summary>
		/// Writes this control message instance to the specified stream.
		/// </summary>
		/// <param name="writer">The writer.</param>
		public void WriteTo(StreamWriter writer)
		{
			if(!string.IsNullOrEmpty(Boundary))
			{
				writer.WriteLine("--{0}", Boundary);
				writer.WriteLine("Content-Type: application/xml");
				writer.WriteLine();
			}
			WriteControl(writer);
			writer.WriteLine();

			if (_content != null)
			{
				writer.WriteLine("--{0}", Boundary);
				_content.WriteTo(writer);
				writer.WriteLine();
				writer.WriteLine("--{0}--", Boundary);
			}
		}

		private void WriteControl(StreamWriter writer)
		{
			XmlWriterSettings settings =
				new XmlWriterSettings
				{
					CheckCharacters = true,
					CloseOutput = false,
					ConformanceLevel = ConformanceLevel.Document,
					Encoding = writer.Encoding,
					Indent = true,
					IndentChars = "  ",
					OmitXmlDeclaration = false
				};
			using (XmlWriter xmlWriter = XmlTextWriter.Create(writer, settings))
			{
				xmlWriter.WriteStartDocument();
				if (_control.IsUsingPublicPush)
				{
					xmlWriter.WriteDocType("pap",
						"-//WAPFORUM//DTD PAP 2.1//EN",
						"http://www.openmobilealliance.org/tech/DTD/pap_2.1.dtd",
						null);
				}
				else
				{
					xmlWriter.WriteDocType("pap",
						"-//WAPFORUM//DTD PAP 2.0//EN",
						"http://www.wapforum.org/DTD/pap_2.0.dtd",
						"<?wap-pap-ver supported-versions=\"2.0,1.*\"?>");
				}

				// Write pap element
				// TODO: Fetch this value from configuration
				object root = null;
				if (UseRimSpecificRoot)
				{
					root = new BpdsRoot
						{
							Request = _control
						};
				}
				else
				{
					root = new PapRoot
						{
							ProductName = "Aero Mobile",
							Request = _control
						};
				}

				XmlSerializer xmlSerializer = new XmlSerializer(root.GetType());
				xmlSerializer.Serialize(xmlWriter, root);

				xmlWriter.WriteEndDocument();
			}
		}
	}
}
